﻿using System.Text.Json.Serialization;
using Core.Caching;
using Core.Domain.Enums;
using Core.Domain.ValueObjects;
using Core.Helpers;
using Core.Identity.Common.Interfaces.Common.Interfaces;
using Core.Identity.Menus.Caching;
using Core.Models;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace Core.Identity.Menus.Features.Commands.Update;

/// <summary>
/// 修改菜单
/// </summary>
public class UpdateMenuCommand : ICacheInvalidatorRequest<Result<bool>>
{
    /// <summary>
    /// 唯一标识
    /// </summary>
    public required Guid Id { get; set; }

    /// <summary>
    /// 编码
    /// </summary>
    public required string Code { get; set; }
    /// <summary>
    /// 名称
    /// </summary>
    public required string Name { get; set; }
    /// <summary>
    /// 分组
    /// </summary>
    public string? Group { get; set; }
    /// <summary>
    /// 父级菜单Id
    /// </summary>
    public Guid? ParentId { get; set; }
    ///// <summary>
    ///// 菜单元数据
    ///// </summary>
    public required MenuMeta Meta { get; set; }
    /// <summary>
    /// 设置描述
    /// </summary>
    public string? Description { get; set; }
    /// <summary>
    /// 设置启用/禁用
    /// </summary>
    public bool Enabled { get; set; }
    /// <summary>
    /// 权限作用域
    /// </summary>
    public PermissionScope Scope { get; set; }

    [JsonIgnore]
    public string CacheKey => MenusCacheKey.GetAllCacheKey;

    [JsonIgnore]
    public IEnumerable<string>? Tags => MenusCacheKey.Tags;
}

public class UpdateMenuCommandHandler(IIdentityDbContext dbContext) : IRequestHandler<UpdateMenuCommand, Result<bool>>
{

    public async Task<Result<bool>> Handle(UpdateMenuCommand request, CancellationToken cancellationToken)
    {
        var menu = await dbContext.Permissions
            .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken);
        ExceptionHelper.ThrowIfNull(menu, "数据不存在");

        if (menu!.Code != request.Code)
        {
            if (!string.IsNullOrWhiteSpace(request.Code))
            {
                var used = await dbContext.Permissions
                    .AnyAsync(x => x.Code == request.Code && x.Id != request.Id, cancellationToken);

                ExceptionHelper.ThrowIfTrue(used, "权限编码已被占用");
            }
            menu.ChangeCode(request.Code);
        }

        // 更新父级（关键：防止循环依赖）
        if (menu!.ParentId != request.ParentId)
        {
            if (menu.ParentId != null && request.ParentId.HasValue)
            {
                var newParent = await dbContext.Permissions
                    .FirstOrDefaultAsync(x => x.Id == request.ParentId.Value, cancellationToken);

                ExceptionHelper.ThrowIfNull(newParent, "父级不存在");

                bool createsCycle = await CheckForCycleAsync(menu.Id, request.ParentId.Value, cancellationToken);
                ExceptionHelper.ThrowIfTrue(createsCycle, "不能将设置为其自身的子节点或后代节点，以避免循环依赖。");
            }

            menu.ChangeParent(request.ParentId);
        }

        // 调试：检查 Meta 是否被识别为复杂属性

        menu!.UpdateMeta(request.Meta);
        menu!.Rename(request.Name);
        menu!.MoveToGroup(request.Group);
        menu.ChangeScope(request.Scope);

        menu.Sort = request.Meta.Rank;
        menu.Description = request.Description;
        menu.Enabled = request.Enabled;

        dbContext.Permissions.Update(menu);

        var result = await dbContext.SaveChangesAsync(cancellationToken) > 0;
        return await Result<bool>.SucceedAsync(result, result, ["修改失败"]);
    }

    private async Task<bool> CheckForCycleAsync(Guid nodeId, Guid potentialParentId, CancellationToken cancellationToken)
    {
        var currentId = potentialParentId;
        const int maxDepth = 100; // 防止无限循环（深度限制）
        int depth = 0;

        while (currentId != Guid.Empty && depth < maxDepth)
        {
            if (currentId == nodeId)
            {
                return true; // 发现闭环
            }

            var parent = await dbContext.Permissions
                .Where(o => o.Id == currentId)
                .Select(o => o.ParentId)
                .FirstOrDefaultAsync(cancellationToken);

            currentId = parent.Value; // 继续向上查找
            depth++;
        }

        return false; // 无环
    }
}
